/*
 *  Copyright (C) 2010 Matthias Buch-Kromann <mbk.isv@cbs.dk>
 * 
 *  This file is part of the IncrementalParser package.
 *  
 *  The IncrementalParser program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Lesser General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 * 
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Lesser General Public License for more details.
 * 
 *  You should have received a copy of the GNU Lesser General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package org.osdtsystem.incparser.graphs;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.osdtsystem.incparser.features.FeatureVector;
import org.osdtsystem.incparser.features.FeatureVectorSparse;

/**
 *
 * @author Matthias Buch-Kromann <mbk.isv@cbs.dk>
 */
abstract class AbstractGraph implements Graph {
    abstract AbstractBaseGraph _baseGraph();
    abstract AbstractGraph _writeToBaseGraphRW();
    abstract AbstractLocalGraph _localGraphRW(int node, int layer);
    abstract void _updateLocalScoreBest(int node, int scorer, float localScore);
    abstract void _notifyOff();
    abstract void _notifyOn();
    abstract boolean _isNotificationOn();

    // Standard node features
    static int INITIALINTFEATURECOUNT = 1;
    static int INITIALOBJECTFEATURECOUNT = 0;
    static int INTFEATURE_LAYER = 0;

    // Bit encoding parameters computed from previous parameters -- do not change!
    final static int OTHERMASK = 0xfffffff >>> NODEBITS;
    final static int NODEMASK = 0xffffffff ^ OTHERMASK;

    // Convenient aliases for bit encoding
    final static int TYPEMASK = OTHERMASK;
    final static int SCORERMASK = OTHERMASK;


    public FeatureVector featureVector() {
        FeatureVector featureVector = new FeatureVectorSparse();
        for (int scorerID = 0; scorerID < scorers(); ++scorerID) {
            GraphScorer scorer = scorer(scorerID);
            scorer.featureVectorAddTo(this, featureVector);
        }
        return featureVector;
    }

    public float localScore(int node) {
        double localScore = 0;
        for (int scorer = 0; scorer < scorers(); ++scorer)
            localScore += localScore(node, scorer);
        return (float) localScore;
    }

    public void writeToFile(String outputFile) {
        Writer writer = null;
        try {
            writer = new PrintWriter(outputFile, "UTF-8");
            writeToFile(writer);
            writer.close();
        } catch (FileNotFoundException ex) {
            Logger.getLogger(AbstractGraph.class.getName()).log(Level.SEVERE, null, ex);
        } catch (UnsupportedEncodingException ex) {
            Logger.getLogger(AbstractGraph.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(AbstractGraph.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public void writeToFile(Writer writer) throws IOException {
        // Parameters
        String scoreFormat = "%6g";

        // Write general graph statistics
        writer.write(getClass().getSimpleName());
        writer.write(": layers=" + layers());
        writer.write(" nodes=" + nodes());
        writer.write(" intFeats=" + intFeatures());
        writer.write(" objFeats=" + objectFeatures());
        writer.write(" scorers=" + scorers());
        writer.write(" score=" + String.format(scoreFormat, score()));
        writer.write("\n");

        // Print nodes
        for (int node = 0; node < nodes(); ++node) {
            // Write node
            writer.write(node + ": int=");

            // Write int features
            String sep = "";
            for (int feature = 0; feature < intFeatures(); ++feature) {
                writer.write(sep + intFeature(node, feature));
                sep = ":";
            }

            // Write in-coming edges in layers
            writer.write(" in=");
            for (int layer = 0; layer < layers(); ++layer) {
                LocalGraph localGraph = localGraph(node, layer);
                if (localGraph.inDegree() > 0) {
                    writer.write(layer + "[");
                    for (int i = 0; i < localGraph.inDegree(); ++i) {
                        int head = localGraph.inEdgeNode(i);
                        int type = localGraph.inEdgeType(i);
                        writer.write(head + "/" + type);
                    }
                    writer.write("] ");
                }
            }

            // Write scores
            if (scorers() > 0) {
                sep = "";
                writer.write(" score=");
                for (int scorer = 0; scorer < scorers(); ++scorer) {
                    writer.write(String.format(scoreFormat, localScore(node, scorer)));
                    writer.write(sep);
                    sep = ":";
                }
            }

            writer.write("\n");
        }
    }
}
